/*******************************************************************************

ATTENTION, this is an altered version of the xhtml_gen library, specifically tailored to libwebconf's needs please refer to the original library

xhtml_gen: xhtml generation library.
Copyright (c) 2006  Mitchel Haas

This software is provided 'as-is', without any express or implied warranty. 
In no event will the author be held liable for any damages arising from 
the use of this software.

Permission is granted to anyone to use this software for any purpose, 
including commercial applications, and to alter it and redistribute it freely, 
subject to the following restrictions:

1.	The origin of this software must not be misrepresented; 
you must not claim that you wrote the original software. 
If you use this software in a product, an acknowledgment in the product 
documentation would be appreciated but is not required.

2.	Altered source versions must be plainly marked as such, 
and must not be misrepresented as being the original software.

3.	The above copyright notice and this permission notice may not be removed 
or altered from any source distribution.

For complete documentation on this library, see http://www.datasoftsolutions.net
Email questions, comments or suggestions to mhaas@datasoftsolutions.net
*******************************************************************************/

#include "tag.hpp"                                                                                                                                                                                                                           
namespace xhtml_gen
{


tag_trait_manager xhtml_gen::tag::pTag_trait_mgr;



tag::tag()  : content(),  pTag_trait(0)
{
}

tag::tag(xhtml_strict _tag) : content(), pTag_trait(pTag_trait_mgr.get_tag_trait(_tag))
{
}

tag::~tag()
{
	pTag_trait = 0;
}

std::string tag::get_attribute( const attribute _attribute ) const
{
	const std::map<attribute, std::string>::const_iterator mi = attributes.find(_attribute);
	if ( mi != attributes.end() ) {
		return mi->second;
	}

	return "";
}

std::string tag::get_style( const css_property _property ) const
{
	const std::map<css_property, std::string>::const_iterator mi = styles.find(_property);
	if ( mi != styles.end() ) {
		return mi->second;
	}

	return "";
}

bool tag::set_attribute( const attribute _attribute, const std::string& _value ) 
{ 
	if (pTag_trait->check_attribute(_attribute)) {
		attributes[_attribute] = _value;
		return true;
	} 
	return false;
}

bool tag::set_style( const css_property _property, const std::string& _value ) 
{ 
	if (pTag_trait->check_style(_property)) {
		styles[_property] = _value; 
		return true;
	}
	return false;
}

//#include <boost/lexical_cast.hpp>
//using boost::lexical_cast;
std::string tag::get_attributes() const
{
	std::ostringstream attributeStr;

	std::map<attribute,std::string>::const_iterator mi = attributes.begin();
	const std::map<attribute,std::string>::const_iterator mi_end = attributes.end();
	for ( ; mi != mi_end; ++mi ) 
		attributeStr << " " << pTag_trait->get_attribute_name(mi->first) << " = \'" << mi->second << "\' ";

	return attributeStr.str();
}

std::string tag::get_styles() const
{
	if ( styles.empty() )
		return "";

	std::ostringstream style_str;
	style_str << " style = \'";

	std::map<css_property,std::string>::const_iterator mi = styles.begin();
	const std::map<css_property,std::string>::const_iterator mi_end = styles.end();
	for ( ; mi != mi_end; ++mi ) {
		style_str << (mi == styles.begin() ? "" : " ") << get_css_property_name(mi->first) << ":" << mi->second << ";";
	}
	style_str << "\' ";

	return style_str.str();
}

std::string tag::get_xhtml(const int _indent) const
{
	if (!pTag_trait)
		throw std::domain_error("pTag_trait invlaid");

	std::ostringstream ostr;

	if (pTag_trait->get_nesting_type() != in_line)
		ostr << std::string(_indent *3, ' ');

	ostr << "<" << get_tag_name() 
		<< get_attributes() << get_styles()
		<< (pTag_trait->get_nesting_type() == empty ? "/" : "") 
		<< (pTag_trait->get_nested_type() == empty ? "/" : "") << ">";

	if (pTag_trait->get_nesting_type() != in_line)
		ostr << "\n";

	return ostr.str();
}

std::string tag::get_end_tag(const int _indent) const
{
	if (!pTag_trait)
		throw std::domain_error("pTag_trait invlaid");

	std::ostringstream ostr;
	if ( pTag_trait->get_nested_type() != empty ) {

		if (pTag_trait->get_nesting_type() != in_line)
			ostr << std::string(_indent * 3, ' ');

		ostr << "</" << get_tag_name() << ">";
		
		if (pTag_trait->get_nesting_type() != in_line)
			ostr << "\n";

	}
	return ostr.str();
}

xhtml_strict tag::get_tag_enumeration() const 
{ 
	return pTag_trait->get_tag_enumeration(); 
}

std::string tag::get_tag_name() const 
{ 
	return pTag_trait->get_tag_name(); 
}

bool tag::validate_nesting(const tag* _childTag) const 
{
	const tag_trait* pChildTrait = _childTag->get_tag_trait();

	// check for non-flow nested types
	if (pTag_trait->get_nested_type() == non_flow) {
		const std::set<xhtml_strict>& nested_tags = pTag_trait->get_nested_tags();
		const std::set<xhtml_strict>::const_iterator tag_it = nested_tags.find(_childTag->get_tag_enumeration());
		return (tag_it != nested_tags.end());
	}

	// check for flow types
	if (pTag_trait->get_nested_type() == pChildTrait->get_nesting_type()
		|| (pTag_trait->get_nested_type() == flow && (pChildTrait->get_nesting_type() == block || pChildTrait->get_nesting_type() == in_line))) {
			const std::set<xhtml_strict>& nested_exceptions = pTag_trait->get_nested_exceptions();
			const std::set<xhtml_strict>::const_iterator tag_it = nested_exceptions.find(_childTag->get_tag_enumeration());
			return (tag_it == nested_exceptions.end());
		}

	return false;
}

bool tag::allow_cdata() const 
{ 
	return (pTag_trait->get_nested_type() == flow || pTag_trait->get_nested_type() == in_line || pTag_trait->get_nested_type() == cdata ); 
}

nesting_type tag::get_nesting_type() const 
{ 
	return pTag_trait->get_nesting_type(); 
}

}
